package top.v5it.japi.plus.data.jpa.repository.query;

import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.util.Streamable;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * jpa工具类，拼接sql，组装参数
 *
 * @author zhanpu
 * @date 2021/3/19
 */
@Slf4j
public class JapiQueryUtil {

    private static final String EQUALS_CONDITION_STRING = "%s.%s = :%s";
    private static final String UPDATE_STRING = "update %s x";
    private static final String SET_CONDITION_STRING = EQUALS_CONDITION_STRING;

    private JapiQueryUtil() {
        throw new UnsupportedOperationException();
    }

    /**
     * 拼接update语句
     *
     * @param entityName    实体对象名称
     * @param whereProperty 条件字段
     * @param entityMap     实体对象
     * @return hql语句
     */
    public static String getDynamicUpdateString(String entityName, Iterable<String> whereProperty, Map<String, Object> entityMap) {

        Assert.isTrue(whereProperty.iterator().hasNext(), "条件参数为空");

        //拼接where
        String whereClause = Streamable.of(whereProperty).stream()
                .map(s -> String.format(EQUALS_CONDITION_STRING, "x", s, s))
                .collect(Collectors.joining(" AND ", " WHERE ", ""));

        //将id名转换成功set
        Set<String> whereSet = Streamable.of(whereProperty).toSet();

        //拼接set
        String setClause = Streamable.of(entityMap.entrySet()).stream().filter(e -> !whereSet.contains(e.getKey())).map(Map.Entry::getKey)
                .map(s -> String.format(SET_CONDITION_STRING, "x", s, s)).collect(Collectors.joining(", ", " SET ", ""));

        return QueryUtils.getQueryString(UPDATE_STRING, entityName) + setClause + whereClause;
    }

    /**
     * 绑定参数并返回{@link Query}对象
     *
     * @param updateString  hql语句
     * @param entityMap     实体对象
     * @param entityManager 实体管理器
     * @return {@link Query}对象
     */
    public static Query applyAndBind(String updateString, Map<String, Object> entityMap, EntityManager entityManager) {

        Query query = entityManager.createQuery(updateString);
        entityMap.entrySet().iterator().forEachRemaining(entry -> query.setParameter(entry.getKey(), entry.getValue()));

        return query;
    }
}
